package service

import (
	"bilichatroom/model/model"
	"bilichatroom/model/req_resp"
	"bilichatroom/pkg/DB"
	"bilichatroom/pkg/util/gojson"
	"bilichatroom/service/enum/msg_type_enum"
	"bilichatroom/service/enum/user_status_enum"
	"fmt"
	"golang.org/x/net/websocket"
	"time"
)

type BiliSocketService struct {
	sockets []*VideoSocket
}

type VideoSocket struct {
	Video    string
	NickName string
	ws       *websocket.Conn
}

func (self *BiliSocketService) Connect(ws *websocket.Conn) {
	var err error
	msg := req_resp.MsgReq{}
	for {
		var reply string
		if err = websocket.Message.Receive(ws, &reply); err != nil {
			if err.Error() == "EOF" {
				fmt.Println("用户退出: ", msg)
				self.OffLine(&msg)
			} else {
				fmt.Println("未知错误 : ", err)
			}
			break
		}

		if err := gojson.UnmarshalFromString(reply, &msg); err != nil {
			fmt.Println("消息解析失败 ERR: ")
			continue
		}
		if msg.Type != msg_type_enum.Heartbeat {
			fmt.Println("收到消息： ", reply)
		}

		//消息处理
		switch msg.Type {
		case msg_type_enum.Login:
			self.Login(&msg, ws)
		case msg_type_enum.Message:
			self.GetNewMsg(&msg, ws)
		case msg_type_enum.History:
			self.GetHistoryMsg(&msg, ws)
		case msg_type_enum.Heartbeat:
			self.HeartBeat(&msg, ws)
		case msg_type_enum.ChangeName:
			self.ChangeName(&msg, ws)
		}
	}
}

//修改昵称
func (self *BiliSocketService) ChangeName(msg *req_resp.MsgReq, ws *websocket.Conn) {
	user := model.User{}
	has, err := DB.Where("video = ? and name = ?", msg.Video, msg.Name).FindOne(&user)
	if err != nil {
		fmt.Println("数据库查询出错[ChangeName] ", err)
		return
	}
	if !has {
		return
	}
	user.Name = msg.Content
	if _, err = DB.UpdateById(user.Id, &user); err != nil {
		fmt.Println("数据库更新错误[ChangeName] ", err)
		return
	}
	fmt.Println("昵称已修改 ", user.Name)
}

//心跳，返回在线用户列表
func (self *BiliSocketService) HeartBeat(msg *req_resp.MsgReq, ws *websocket.Conn) {
	//查询在线用户列表
	userList := []*model.User{}
	if err := DB.Where("video = ? and status = 'online'", msg.Video).FindRows(&userList); err != nil {
		fmt.Println("数据库查询出错[70]", err)
		return
	}
	//fmt.Println("心跳查询在线用户： ", gojson.MarshalToString(userList))

	userResp := model.UserResp{
		Data: userList,
		Type: "heartbeat",
	}
	if err := websocket.Message.Send(ws, gojson.MarshalToString(userResp)); err != nil {
		fmt.Println("消息发送失败[47]: ", err.Error())
	}
}

//新连接存入socket数组、存入数据库、更新在线人数
func (self *BiliSocketService) Login(msg *req_resp.MsgReq, ws *websocket.Conn) {
	videoSocket := VideoSocket{
		Video:    msg.Video,
		NickName: msg.Name,
		ws:       ws,
	}
	self.sockets = append(self.sockets, &videoSocket)
	fmt.Println("有新用户上线了，当前在线人数： ", len(self.sockets))
	//查询数据库，查看是否已经存在记录，存在则更新状态，不存在则新增
	user := model.User{}
	has, err := DB.Where("name = ? and video = ?", msg.Name, msg.Video).FindOne(&user)
	if err != nil {
		fmt.Println("数据库查询出错[90]： ", err.Error())
		return
	}
	//如果不存在该记录，则插入
	if !has {
		user.Name = msg.Name
		user.Video = msg.Video
		user.Status = user_status_enum.Online
		if _, err := DB.InsertOne(&user); err != nil {
			fmt.Println("数据库插入出错[79]： ", err.Error())
			return
		}
	} else {
		//如果存在该记录，则更新状态为在线
		user.Status = user_status_enum.Online
		if _, err := DB.UpdateById(user.Id, &user); err != nil {
			fmt.Println("数据库更新出错[86]： ", err.Error())
			return
		}
	}

	//查询该房间最近半小时的聊天记录，存在则返回
	room := model.Room{}
	has, err = DB.Where("video = ?", msg.Video).FindOne(&room)
	if err != nil {
		fmt.Println("数据库查询出错[95]: ", err.Error())
		return
	}
	//如果之前不存在该房间，那么新增房间后无需返回数据，结束
	if !has {
		//新建房间记录
		room.Video = msg.Video
		room.Number = 1
		if _, err = DB.InsertOne(&room); err != nil {
			fmt.Println("数据库插入出错[103]: ", err.Error())
			return
		}
		return
	} else {
		room.Number++
		if _, err = DB.UpdateById(room.Id, &room); err != nil {
			fmt.Println("在线人数更新失败: ", err.Error())
			return
		}
	}
	return
}

//新聊天记录
func (self *BiliSocketService) GetHistoryMsg(msg *req_resp.MsgReq, ws *websocket.Conn) {
	//查询该房间最近半小时的聊天记录，存在则返回
	room := model.Room{}
	has, err := DB.Where("video = ?", msg.Video).FindOne(&room)
	if err != nil {
		fmt.Println("数据库查询出错[95]: ", err.Error())
		return
	}
	//如果之前不存在该房间，那么新增房间后无需返回数据，结束
	if !has {
		//新建房间记录
		room.Video = msg.Video
		room.Number = 1
		if _, err = DB.InsertOne(&room); err != nil {
			fmt.Println("数据库插入出错[103]: ", err.Error())
			return
		}
		return
	}

	//查询半小时内的记录
	historys := []*model.History{}
	if err = DB.Where("room_id = ? and created_at > DATE_SUB(NOW(),INTERVAL 30 MINUTE)",
		room.Id).FindRows(&historys); err != nil {
		fmt.Println("数据库查询出错[114]： ", err.Error())
		return
	}
	fmt.Println(room.Id, " ", room.Video, " 近半小时发言数：", len(historys))
	if len(historys) == 0 {
		return
	}

	resp := model.HistoryResp{
		Type: "history",
		Data: historys,
	}
	//返回历史记录给用户
	historyStr := gojson.MarshalToString(resp)
	if err = websocket.Message.Send(ws, historyStr); err != nil {
		fmt.Println("消息发送失败[120]: ", err.Error())
	}
	return
}

func (self *BiliSocketService) OffLine(msg *req_resp.MsgReq) {
	user := model.User{}
	has, err := DB.Where("name = ? and video = ?", msg.Name, msg.Video).FindOne(&user)
	if err != nil {
		fmt.Println("数据库查询出错[149]： ", err.Error())
		return
	}
	if !has {
		fmt.Println("压根没存这个用户的记录，没法退出。我说你代码写的是不是有问题啊")
		return
	}

	for i := 0; i < len(self.sockets); i++ {
		if msg.Name == self.sockets[i].NickName && msg.Video == self.sockets[i].Video {
			self.sockets = append(self.sockets[:i], self.sockets[i+1:]...)
		}
	}

	if _, err := DB.DeleteById(user.Id, &user); err != nil {
		fmt.Println("用户删除失败[152]: ", err.Error())
	}

	fmt.Println("用户记录删除")
}

//新聊天记录
func (self *BiliSocketService) GetNewMsg(msg *req_resp.MsgReq, ws *websocket.Conn) {
	room := model.Room{}
	has, err := DB.Where("video = ?", msg.Video).FindOne(&room)
	if err != nil {
		fmt.Println("数据库查询出错[130]: ", err.Error())
		return
	}
	//如果之前不存在该房间，那么新增房间
	if !has {
		room.Video = msg.Video
		room.Number = 1
		id, err := DB.InsertOne(&room)
		if err != nil {
			fmt.Println("数据库插入出错[139]: ", err.Error())
			return
		}
		fmt.Println("新增了个房间，房间ID为 ", id)
		room.Id = id
	}
	fmt.Println("消息所属房间: ", gojson.MarshalToString(room))

	user := model.User{}
	has, err = DB.Where("name = ? and video = ?", msg.Name, msg.Video).FindOne(&user)
	if err != nil {
		fmt.Println("数据库查询出错[149]： ", err.Error())
		return
	} //如果不存在该记录，则插入
	if !has {
		user.Name = msg.Name
		user.Video = msg.Video
		user.Status = user_status_enum.Online
		id, err := DB.InsertOne(&user)
		if err != nil {
			fmt.Println("数据库插入出错[157]： ", err.Error())
			return
		}
		user.Id = id
	}
	fmt.Println("消息所属用户: ", gojson.MarshalToString(user))

	//保存到数据库
	history := model.History{
		RoomId:    room.Id,
		UserId:    user.Id,
		UserName:  user.Name,
		Content:   msg.Content,
		CreatedAt: time.Now(),
	}
	if _, err = DB.InsertOne(&history); err != nil {
		fmt.Println("数据库插入出错[173]: ", err.Error())
		return
	}
	//给所有处于该房间的socket发送该信息，除了发送者
	tempList := []*model.History{}
	tempList = append(tempList, &history)
	for i := 0; i < len(self.sockets); i++ {
		resp := model.HistoryResp{
			Type: "history",
			Data: tempList,
		}
		historyStr := gojson.MarshalToString(resp)
		fmt.Println("广播消息： ", historyStr)
		if err = websocket.Message.Send(self.sockets[i].ws, historyStr); err != nil {
			fmt.Println("消息发送失败[182]: ", err.Error())
		}
		//}
	}
}
